#ifndef IBE_ABAQUS_ODB_READER_H_
#define IBE_ABAQUS_ODB_READER_H_

#include <map>
#include <vector>

#include <odb_API.h>

#include "IBE_Abaqus_Export.h"
#include "IBE_DataInformationClasses.h"
#include "IBE_ObjectReader.h"

namespace ibe_abaqus
{
    /**
      * @class IBE_AbaqusOdbReader
      * @brief 解析ABAQUS的odb文件
    */
    class IBE_ABAQUS_EXPORT IBE_AbaqusOdbReader : public ibe_common::IBE_ObjectReader
    {
    public:
        explicit IBE_AbaqusOdbReader( const char* file_name = "" );
        ~IBE_AbaqusOdbReader();
        IBE_TypeMacro( ibe_abaqus, IBE_AbaqusOdbReader, ibe_common, IBE_ObjectReader );

        virtual void Update() override;

        virtual std::map<std::string, std::map<int, int>> GetInstancePointLabelIdMap();
        virtual std::map<std::string, std::map<int, int>> GetInstanceCellLabelIdMap();

    protected:
        virtual void Initialize() override;
        virtual void InitData() override;

        /**
         * @brief 读取odb文件
         *
         * @param file_name odb文件路径
         */
        virtual void ReadOdb( const char* file_name );

        /**
         * @brief 获取一个临时文件的路径
         * @return 文件路径
         */
        virtual std::string GetTempFileNameOfOdb();

        /**
        * @brief 将odb单元几何类型转换为vtk单元类型
        *
        * @param elementGeometry odb单元几何类型
        * @return vtk单元类型，VTK_VERTEX、VTK_LINE等
        */
        virtual int GetVtkCellTypeByOdbElementGeometry(
            const odb_Enum::odb_ElementGeometryClass &elementGeometry );

        /**
         * @brief 通过odb子单元信息获取其在对应vtk单元中的索引和类型
         *
         * @param elementGeometry odb子单元的原始单元类型
         * @param elementFace odb子单元位置
         * @return 第一个为子单元在原始单元(该原始单元为转换后的vtk单元)中的索引，
         * 第二个为子单元类型(VTK_VERTEX、VTK_LINE等)
         */
        virtual std::vector<int> OdbFaceToVtkSubCell(
            const odb_Enum::odb_ElementGeometryClass &elementGeometry,
            const odb_Enum::odb_ElementFaceEnum &elementFace );

        /**
         * @brief 网格集集合odb_SetRepository类型
         */
        enum SetRepositoryType
        {
            IBE_SET_REPOSITORY_NODE = 0,    //!< node
            IBE_SET_REPOSITORY_ELEMENT,     //!< element
            IBE_SET_REPOSITORY_SURFACE      //!< surface
        };

        //@{
        /**
         * @brief 从Odb_Instance,Odb_Part,Odb_Assembly中获取网格集
         *
         * @param discreteEntity Odb_Instance,Odb_Part,Odb_Assembly的父类
         * @return 第一个是节点集，第二个是单元集，第三个是子单元集
         */
        virtual std::vector<std::vector<ibe_common::IBE_Block*>> AnalyzeOdbSets(
            odb_DiscreteEntity* discreteEntity, const std::string &prefix = "" );
        /**
         * @brief 解析odb_SetRepository获取网格集数据
         *
         * @param setRep 网格集集合
         * @param repType odb_SetRepository的类型，SetRepositoryType枚举值
         * @param prefix 网格集名称前缀
         * @return 解析后网格集的容器
         */
        virtual std::vector<ibe_common::IBE_Block*> AnalyzeOdbSets(
            odb_SetRepository &setRep, const int &repType, const std::string &prefix = "" );
        virtual std::vector<ibe_common::IBE_Block*> AnalyzeOdbNodeSets(
            odb_SetRepository &setRep, const std::string &prefix = "" );
        virtual std::vector<ibe_common::IBE_Block*> AnalyzeOdbElementSets(
            odb_SetRepository &setRep, const std::string &prefix = "" );
        virtual std::vector<ibe_common::IBE_Block*> AnalyzeOdbSurfaceSets(
            odb_SetRepository &setRep, const std::string &prefix = "" );
        /**
         * @brief 解析单个网格集
         *
         * @param set 单个网格集odb_Set
         * @param blockType 网格集的类型，ibe_common::IBE_Block::IBE_BlockType枚举值
         * @param blockName 网格集名称
         * @return 解析后的单个网格集
         */
        virtual ibe_common::IBE_Block* AnalyzeOdbSet(
            odb_Set &set, const int &blockType, const std::string &blockName );
        //@}

        /**
         * @brief odb节点对应的odb单元，及节点在单元中的序号
         */
        struct ElementOfNode
        {
            odb_Element element; //! 节点所在单元
            int location; //! 节点在单元中的位置（序号）
        };

        /**
         * @brief 获取节点对应的单元信息
         *
         * @param mesh 网格
         * @param node 节点
         * @return odb节点对应的单元信息
         */
        virtual std::vector<ElementOfNode> GetElementOfNode( const odb_Mesh &mesh, const odb_Node &node );

        /**
         * @brief 解析物理场数据
         *   
         * @param field 物理场
         * @param fieldName 物理场名称
         * @return 解析后的物理场信息
         */
        virtual ibe_common::IBE_FieldData* AnalyzeFieldInfo(odb_FieldOutput &field, std::string fieldName);

    protected:
        //! 点坐标键值对：odb节点的label与索引
        std::map<odb_String, std::map<int, int>> instance_point_label_id_map_;
        //! 单元键值对：odb单元的label与索引
        std::map<odb_String, std::map<int, int>> instance_cell_label_id_map_;

    private:
        IBE_AbaqusOdbReader( const IBE_AbaqusOdbReader& ) = delete;
        IBE_AbaqusOdbReader& operator=( const IBE_AbaqusOdbReader& ) = delete;
    };

} // namespace ibe_abaqus

#endif // IBE_ABAQUS_ODB_READER_H_